/**
 * #info
 *
 *@author   yuanzhy
 *@createTime   2018/06/08
 *@updateTime   2018/06/08
 *@description  organ-tree  component  组织机构组件
 */
/**
 * #item
 *
 * @type       aty-organ-tree
 * @cn            组织机构
 * @nameprop    label
 * @menu        表单
 * @stPlugin    true
 * @stContainer false
 * @mixins      [./components/components/form/form-item/form-item.js]
 */
import config from '../../../config/config.js'
// components
import Icon from '../../basic/icon/index.vue'
import Drop from '../../form/select/dropdown/index.vue'
// import FormItem from '../form-item/index.vue'
import tree from '../../navigation/tree/index.vue'
// directives
import clickoutside from '../../../directives/clickoutside'
import TransferDom from '../../../directives/transfer-dom'
// mixins
// import FormItemProps from '../../../mixins/form-item-props.js'
import Emitter from '../../../mixins/emitter.js'
import Locale from '../../../mixins/locale.js'
import formItem from '../form-item/form-item.js'
// prefix
const prefixCls = config.prefix + '-organ-tree'
const prefixSelectCls = config.prefix + '-select'
// module
export default {
  name: prefixCls,
  mixins: [Emitter, Locale, /*FormItemProps,*/formItem],
  components: { Icon, Drop,/* FormItem, */tree },
  directives: { clickoutside, TransferDom },
  props: {
    /**
     * #property
     *
     * @name    dropAsync
     * @cn      下拉菜单异步渲染
     * @group   控制
     * @type    Boolean
     * @description 下拉菜单是否异步渲染dom，默认为true
     */
    dropAsync: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name   selectScope
     * @cn     选择范围
     * @group  控制
     * @type    list
     * @options  [all, csCorp, corp, csDept, dept]
     * @value   all
     * @description all:全部, csCorp:本单位和下级单位, corp:本单位, csDept:本部门和子部门, dept:本部门, cpCorp: 本单位及上级单位
     */
    selectScope: {
      validator (value) {
        return Artery.isOneOf(value, ['all', 'csCorp', 'corp', 'csDept', 'dept', 'cpCorp'])
      },
      default: 'all'
    },
    /**
     * #property
     *
     * @name   selectType
     * @cn     选择类型
     * @group  控制
     * @type    list
     * @options  [user, dept, corp, corp_dept, all]
     * @value   all
     * @description 标识可选哪些类型的组织机构
     */
    selectType: {
      validator (value) {
        return Artery.isOneOf(value, ['user', 'dept', 'corp', 'corp_dept', 'all'])
      },
      default: 'all'
    },
    /**
     * #property
     *
     * @name   rightKeys
     * @cn     权限字
     * @group  控制
     * @type    string, array
     * @version  1.0.2
     * @description 只显示拥有该权限字的人员, 权限字数组或逗号拼串
     */
    rightKeys: {
      type: String, Array
    },
    /**
     * #property
     *
     * @name   roleIds
     * @cn     角色
     * @group  控制
     * @type    string, array
     * @version  1.0.2
     * @description 只显示拥有该角色的人员, 角色id数组或逗号拼串
     */
    roleIds: {
      type: String, Array
    },
    /**
     * #property
     *
     * @name   listMode
     * @cn     列表模式
     * @group  控制
     * @type   boolean
     * @value  false
     * @version  1.0.2
     * @description 人员将以下拉列表的形式展现, 仅适用于指定了rightKeys或roleIds的情况
     */
    listMode: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name   rootId
     * @cn     根节点id
     * @group  控制
     * @type   string
     * @description 不推荐使用此参数, 推荐select-scope动态适应根节点
     */
    rootId: {
      type: String
    },
    /**
     * #property
     *
     * @name    value
     * @cn      值
     * @group   数据
     * @type    string,number,array
     * @description 最终提供给后端的值
     */
    value: {
      type: [String, Number, Array]
    },
    /**
     * #property
     *
     * @name    placement
     * @cn      下拉框出现的位置
     * @group  样式
     * @type    list
     * @options [top, bottom]
     * @value  bottom
     * @description 该下拉框出现的位置，取值为 ['top', 'bottom']中的其中一个
     */
    placement: {
      validator (value) {
        return Artery.isOneOf(value, ['top', 'bottom'])
      },
      default: 'bottom'
    },
    /**
     * #property
     *
     * @name   canSearch
     * @cn     是否可搜索
     * @group  控制
     * @type   boolean
     * @bind   must
     * @value  true
     * @description 是否可搜索
     */
    canSearch: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    multiple
     * @cn      是否支持多选
     * @group  控制
     * @type    boolean
     * @value  false
     * @description 是否支持多选
     */
    multiple: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    disabled
     * @cn      是否禁用
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 该下拉树是否禁用
     */
    disabled: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    clearable
     * @cn      是否有清除按钮
     * @group  控制
     * @type    boolean
     * @value  false
     * @description 该下拉框是否有清除按钮
     */
    clearable: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    transfer
     * @cn      是否将弹层放置于 body 内
     * @group  控制
     * @type    boolean
     * @value  false
     * @description  是否将弹层放置于 body 内，
     *              在 Tabs、带有 fixed 的 Table 列内使用时，建议添加此属性，它将不受父级样式影响，从而达到更好的效果
     */
    transfer: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    placeholder
     * @cn      占位文本
     * @group  基本属性
     * @type    string
     * @description 占位文本
     */
    placeholder: {
      type: String
    },
    /**
     * #property
     *
     * @name    searchPlaceholder
     * @cn      搜索框占位文本
     * @group  基本属性
     * @type    string
     * @version  1.0.0
     * @description 搜索框占位文本
     */
    searchPlaceholder: {
      type: String
    },
    /**
     * #property
     *
     * @name    icon
     * @cn      图标
     * @group  基本属性
     * @type    icon
     * @value  ios-search-strong
     * @description 搜索框尾部的图标
     */
    icon: {
      type: String,
      default: 'ios-search-strong'
    },
    /**
     * #property
     *
     * @name    cascade
     * @cn      级联选择
     * @group   控制
     * @type    boolean
     * @value   false
     * @version  1.0.0
     * @description 复选框多选时，是否关联子节点选中
     */
    cascade: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    connectParent
     * @cn      关联父级选中
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 复选框多选时，是否关联父级选中
     */
    connectParent: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    autoRequestData
     * @cn      是否自动请求数据
     * @group  控制
     * @type    boolean
     * @value  false
     * @description 是否自动请求数据, 如果navigation设置为true,则始终会自动请求数据
     */
    autoRequestData: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    lazyLoad
     * @cn      懒加载
     * @group  控制
     * @type    boolean
     * @value  true
     * @bind   must
     * @description 如存在级联选择情况,可将此属性设置为false,组织机构将一次性全部加载出来,注:同步获取节点过多情况在IE下可能会有卡顿
     */
    lazyLoad: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    navigation
     * @cn      是否导航树
     * @group  控制
     * @type    boolean
     * @value  false
     * @description 导航树即不是下拉的树. 一般放在页面左侧做导航使用
     */
    navigation: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    searchShowLimit
     * @cn      搜索框显示搜索结果数量限制
     * @group   控制
     * @type    number
     * @bind    must
     * @value   5
     * @description 搜索框显示搜索结果的数量限制,如果调大搜素框会出现滚动条可能影响效果展示
     */
    searchShowLimit: {
      type: Number,
      default: 5
    },
    /**
     * #property
     *
     * @name    urlPrefix
     * @cn      url前缀
     * @group   url
     * @type    string
     * @description 组织机构接口url前缀, 如指定末尾必须有'/'
     */
    urlPrefix: {
      type: String,
      validator (value) {
        if (value) {
          return value.endsWith('/')
        }
        return true
      },
      default: ''
    },
    /**
     * #property
     *
     * @name    requestDataUrl
     * @cn      请求数据的url
     * @group   url
     * @type    string
     * @value   artery/organ/children
     * @description 请求数据的url，请求参数为
     * {
     * selectType: this.selectType,
     * selectScope: this.selectScope,
     * multiple: 是否多选
     * id: 空则加载根节点
     * type: corp,dept,user
     * }
     */
    requestDataUrl: {
      type: String,
      default: 'artery/organ/children'
    },
    /**
     * #property
     *
     * @name    searchDataUrl
     * @cn      搜索数据的url
     * @group   url
     * @type    string
     * @value   artery/organ/search
     * @description 搜索数据的url，请求参数为
     * {
     * selectType: this.selectType,
     * selectScope: this.selectScope,
     * multiple: 是否多选,
     * searchText: 搜索内容
     * }
     */
    searchDataUrl: {
      type: String,
      default: 'artery/organ/search'
    },
    /**
     * #property
     *
     * @name    translateDataUrl
     * @cn      翻译数据的url
     * @group   url
     * @type    string
     * @value   artery/organ/nodes
     * @description 由于是异步获取下拉数据, 初始化有选中值的情况需要调用此url接口翻译数据, 请求参数为[id1,id2,id3]
     */
    translateDataUrl: {
      type: String,
      default: 'artery/organ/nodes'
    },
    /**
     * #property
     *
     * @name    dropClassName
     * @cn      下拉框css类名
     * @group   url
     * @type    string
     * @description 下拉框css类名
     */
    dropClassName: {
      type: String
    },
    /**
     * #property
     *
     * @name    showIcon
     * @cn      是否显示图标
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 是否显示图标,默认为false
     */
    showIcon: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    pinyinSearch
     * @cn      拼音搜索
     * @group   控制
     * @type    boolean
     * @value   false
     * @description 是否支持拼音搜索, 组织机构目前只有人员支持, 需要User.xmjp字段
     */
    pinyinSearch: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    maxTagCount
     * @cn      最大显示tag数量
     * @group   样式
     * @type    number
     * @bind    must
     * @version  1.0.0
     * @description 最多显示的tag数量，超出部分默认显示"+2...", 可通过max-tag-placeholder自定义描述, 仅适用于多选
     */
    maxTagCount: {
      type: Number,
      validator (value) {
        return Number.isInteger(value) && value > 0
      },
    },
    /**
     * #property
     *
     * @name    maxTagPlaceholder
     * @cn      tag超出后折叠的显示内容
     * @group   样式
     * @type    string
     * @version  1.0.0
     * @description 自定义tag超出后折叠的显示内容, 可使用模板 例: 共选择{max},超出{overflow}项...
     */
    maxTagPlaceholder: {
      type: String
    },
    /**
     * #property
     *
     * @name    dropdownWidth
     * @cn      下拉框宽度
     * @group   样式
     * @type    number
     * @bind    must
     * @description 如不指定和input保持一致, 指定为0则自适应内容宽度
     */
    dropdownWidth: {
      type: Number
    },
    /**
     * #property
     *
     * @name    popupClass
     * @cn      弹出框样式
     * @type    string
     * @description 可自定义弹框的样式或用于定位该元素
     */
    popupClass: {
      type: String
    },
    /**
     * #property
     *
     * @name    showInvalid
     * @cn      显示无效节点
     * @group   控制
     * @type    boolean
     * @value   false
     * @version  1.0.0
     * @description 设置为true后, 无效的组织会以disable的形式展现(需配合Artery6.1.0+)
     */
    showInvalid: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    canSelectDisabled
     * @cn      是否可选择无效的节点
     * @group   控制
     * @type    boolean
     * @value   false
     * @version  1.0.0
     * @description 仅单选使用, 无效节点是否触发select
     */
    canSelectDisabled: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    openOrgans
     * @cn      默认展开的组织
     * @group   控制
     * @type    string, array
     * @version  1.0.2
     * @description 可传递id数组或者id加逗号拼串. 注意: 父组织id也需要声明
     */
    openOrgans: {
      type: String, Array
    },
    /**
     * #property
     *
     * @name    dropDownMaxHeight
     * @cn      下拉数据区域最大高度
     * @group   样式
     * @type    number
     * @value   200
     * @bind    must
     * @description 超出最大高度显示滚动条
     */
    dropDownMaxHeight: {
      type: Number,
      default: 200
    }
  },
  data () {
    return {
      dropLoaded: !this.dropAsync,
      visible: false, // 是否显示下拉框
      prefix: config.prefix, // 前缀
      prefixCls: prefixCls, // 组件前缀
      selectedSingle: {}, // 单选
      selectedMultiple: [], // 多选
      activeId: '',
      checkedIds: [],
      data: [],
      searchStr: '', // 搜索关键字
      searchData: [], // 搜索下拉框中的数据
      searchDropVisible: false, // 搜索下拉框显示状态
      searchInputWidth: 33, // 搜索输入框的基础宽度
      searchItemFocusIndex: 0 // 上下切换时，搜索项的索引号
    }
  },
  watch: {
    // 当前的值
    value (newValue, oldValue) {
      // if (newValue != oldValue) {
        // 设置值
        this.setValue(newValue)
      // }
    },
    visible (val) {
      if (val) {
        // 控制resetDatas
        // if (this.asyncComponentLoaded.resetTree) {
        //   this.resetDatas()
        //   this.asyncComponentLoaded.resetTree = false
        // }
        if (this.dropLoaded) {
          if (!this.navigation && !this.autoRequestData && !this.$refs.tree.currentData.length) {
            this.$refs.tree.initRequestTreeData()
          }
          this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
        } else {
          this.dropLoaded = true
        }
      }
    },
    resetRelated (newValue, oldValue) {
      if (this.visible) {
        this.hideMenu()
      }
      this.resetDatas()
    },
  },
  computed: {
    // 下拉框容器的类名
    classes () {
      return [
                `${prefixCls}`,
                {
                  [`${prefixCls}-visible`]: this.visible,
                  [`${prefixCls}-disabled`]: this.disabled,
                  [`${prefixCls}-multiple`]: this.multiple,
                  [`${prefixCls}-single`]: !this.multiple,
                  [`${prefixCls}-show-clear`]: this.showCloseIcon,
                  [`${prefixCls}-${this.size}`]: !!this.size
                }
      ].concat(this.formItemClasses)
    },
    dropDownListStyles() {
      return {
        overflowY: 'auto',
        maxHeight: `${this.dropDownMaxHeight}px`
      }
    },
    selectionCls () {
      return {
        [`${prefixCls}-selection`]: !this.autoComplete
      }
    },
    // 下拉框的类名
    dropdownCls () {
      return [
        this.elementId ? prefixCls + this.elementId : '',
        this.dropClassName ? this.dropClassName : '',
        {
          [prefixSelectCls + '-dropdown-transfer']: this.transfer
        }
      ]
    },
    dropdownSearchCls () {
      return [prefixSelectCls + '-dropdown-transfer-search'].concat(this.dropdownCls)
    },
    transitionName () {
      return this.placement === 'bottom' ? 'slide-up' : 'slide-down'
    },
    localePlaceholder () {
      if (this.placeholder === undefined) {
        return this.t('i.select.placeholder')
      } else {
        return this.placeholder
      }
    },
    showPlaceholder () {
      let status = false
      if (this.multiple) {
        if (this.selectedMultiple.length == 0) {
          status = true
        }
      } else {
        if (!this.activeId) {
          status = true
        }
      }
      return status
    },
    showCloseIcon () {
      return this.clearable && !this.showPlaceholder
    },
    showEllipsis() {
      return this.maxTagCount && this.maxTagCount < this.selectedMultiple.length
    },
    showMaxTagPlaceholder() {
      if (this.maxTagPlaceholder) {
        return this.maxTagPlaceholder
          .replace('{overflow}', this.selectedMultiple.length - this.maxTagCount)
          .replace('{max}', this.selectedMultiple.length)
      } else {
        return '+' + (this.selectedMultiple.length - this.maxTagCount) + '...'
      }
    },
    showSelectedMultiple() {
      if (this.showEllipsis) {
        return this.selectedMultiple.slice(0, this.maxTagCount)
      } else {
        return this.selectedMultiple
      }
    },
    isRightMode() {
      return this.rightKeys || this.roleIds
    },
    resetRelated () {
      const { rootId, selectScope, selectType, rightKeys, roleIds } = this
      return { rootId, selectScope, selectType, rightKeys, roleIds }
    },
    inputStyle () {
      let style = {};
      if (this.multiple) {
        if (this.showPlaceholder) {
          style.width = '100%';
        } else {
          style.width = `${this.searchInputWidth}px`;
        }
      }
      if (this.$refs.reference) {
        let maxWidth = Artery.getStyle(this.$refs.reference, "width")
        if (maxWidth.indexOf('px')) {
          maxWidth = `${parseInt(maxWidth.replace('px', '')) - 24}px`
        }
        style.maxWidth = maxWidth
        style.flexGrow = 1
      }
      return style;
    }
  },
  methods: {
    /** 异步组件加载之后的回调 */
    asyncComponentsLoaded (componentName) {
      switch (componentName) {
        // 这里不采用drop是因为tree的需要单独处理
        case 'tree':
          if (!this.navigation && !this.autoRequestData && !this.$refs.tree.currentData.length) {
            this.$refs.tree.initRequestTreeData()
          }
          this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
          break
      }
    },
    getValidateValue() {
      return this.multiple ? this.checkedIds : this.activeId
    },
    resetDatas () {
      // this.data = []
      const tree = this.$refs.tree
      if (tree) {
        tree.reload()
      }
    },
    setValue (newValue) { // 这块有问题, 用户绑定的id一般都没前缀, 所以->1.通过自动适配的方式, 2.自己绑定一个类型数据告诉控件他们的类型分别是什么
      if (this._delayEmit) {
        this._delayEmit = false
        return
      }
      this.addIdPrefix(newValue).then(idList => {
        if (this.multiple) {
          this.checkedIds = idList // 多选框的值
        } else { // 单选值
          this.activeId = idList.length ? idList[0] : ''
        }
        if (idList.length) {
          Artery.ajax({
            method: 'POST',
            url: this.urlPrefix + this.translateDataUrl,
            params: {
              id: idList.join(';'),
              selectType: this.selectType,
              selectScope: this.selectScope,
              navigation: this.navigation
            },
            headers: {
              'X-HTTP-Method-Override': 'GET'
            }
          }).then(result => {
            if (this.multiple) {
              this.selectedMultiple = result
            } else if (result.length) {
              this.selectedSingle = result[0]
              this.searchStr = this.selectedSingle.name
            }
          }).catch(error => {
            console.error('获取组织机构数据失败,error=' + JSON.stringify(error))
          })
        } else if (!this.dropLoaded) { // dropAsync=true,并且没有点击过下拉的情况,idList还会空,则清空
          if (this.multiple) {
            this.selectedMultiple = []
          } else {
            this.selectedSingle = {}
            this.searchStr = ''
          }
        } else {
          if (!this.multiple) {
            this.searchStr = ''
          }
        }
        this.validate()
        // else {
        //   this.validate()
        // }
      })
    },
    addIdPrefix (newValue) { // 将用户绑定的组织机构id拼接上类型前缀
      let idList = newValue || []
      idList = Artery.type(idList) === 'array' ? idList : [idList]
      return new Promise((resolve, reject) => {
        if (idList.length) { // 说明传递进来的已经有前缀了, 不做处理
          if (idList[0].indexOf('_') === 4) {
            resolve(idList)
            // 这两种情况, 无法区分用户v-model的是什么类型, 为了旧版本升级不影响, 先上后台问一下吧
          } else if (this.selectType === 'all' || this.selectType === 'corp_dept') {
            console.warn('selectType为all或者corp_dept的情况建议绑定的变量为"corp_123"形式, 否则有重复id将影响使用')
            Artery.ajax.post(
              this.urlPrefix + this.translateDataUrl,
              {
                id: idList.join(';'),
                selectType: this.selectType,
                selectScope: this.selectScope,
                navigation: this.navigation,
              },
              {
                headers: { 'X-HTTP-Method-Override': 'get' }
              }).then(result => {
              resolve(result.map(node => node.id))
              // if (this.multiple) {
              //     // this.selectedMultiple = result
              //     // this.checkedIds = result.map(node => node.id)
              // } /*else if (result.length) {
              //     resolve(result)
              //     // this.selectedSingle = result[0]
              //     // this.activeId = result[0].id
              // } */else {
              //     resolve(result)
              // }
              // this.dispatchEvent('change', newValue)
              // 使用reject吧, 控制台会报错, 不影响使用, 正常all的情况也需要用户指定绑定的前缀, 督促项目规范使用
            }).catch(error => {
              reject(error)
            })
          } else {
            resolve(idList.map(item => this.selectType + '_' + item))
          }
        } else { // 空的直接返回
          resolve(idList)
        }
      })
    },
    getOrganId (nodeId) { // 通过树的id(corp_1234)获取organId
      if (this.multiple) {
        return nodeId.map(id => id.indexOf('_') === 4 ? id.substring(5) : id)
      } else {
        return nodeId && nodeId.indexOf('_') === 4 ? nodeId.substring(5) : nodeId
      }
    },
    copySelectedSingle (selectedSingle) { // 返回给用户的selectSingle的id应该是organId, 不应该带前缀
      const dataCopy = Artery.deepCopy(selectedSingle)
      const treeNodeId = dataCopy.id
      dataCopy.treeNodeId = treeNodeId
      if (treeNodeId) {
        dataCopy.id = treeNodeId.substring(5)
        dataCopy.type = treeNodeId.substring(0, 4)
      }
      if (dataCopy.parentId && dataCopy.parentId.indexOf('_') === 4) {
        dataCopy.parentType = dataCopy.parentId.substring(0, 4)
        dataCopy.parentId = dataCopy.parentId.substring(5)
      }
      return dataCopy
    },
    copySelectedMultiple (selectedMultiple) {
      return selectedMultiple.map(dataCopy => this.copySelectedSingle(dataCopy))
    },
    // 隐藏菜单
    hideMenu () {
      this.visible = false
      this.focusIndex = 0
      this.searchDropVisible = false
      this.searchItemFocusIndex = 0
    },
    // open when focus on Select and press `down` key
    handleFocus () {
      if (!this.visible) {
        this.toggleMenu()
        this.searchDropVisible = false
      }
    },
    handleClose () {
      this.hideMenu()
    },
    toggleMenu () {
      if (this.disabled) {
        return false
      }
      this.visible = !this.visible
      if (this.canSearch) {
        this.$refs.input.focus()
      }
    },
    // 选中树节点
    select (treeNodeData, treeNode, event) {
      /**
       * #event
       *
       * @name    select
       * @param   organData  当前的组织机构数据
       * @param   treeNode  当前的树节点
       * @param   event    event对象
       * @body
       * @description  点击树节点时触发
       */
      this.$emit('select', this.copySelectedSingle(treeNodeData), treeNode, event)
      if (this.multiple) {
        return // 多选的情况需要点击checkbox, 所以点击树节点不需要走事件
      }
      const oldValue = this.selectedSingle
      this.selectedSingle = treeNodeData
      this.setValue(this.selectedSingle.id)
      this.searchStr = this.selectedSingle.name;
      const organId = this.getOrganId(this.selectedSingle.id)
      this.$emit('input', organId)
      this.hideMenu()
      /**
       * #event
       *
       * @name    change
       * @param   newValue 变化后的节点对象或数组
       * @param   oldValue 变化前的节点对象或数组
       * @description  单选时点击节点触发,变化值为对象；多选时点击checkbox触发，变化值为数组
       * @body
       */
      this.$emit('change', this.copySelectedSingle(this.selectedSingle), this.copySelectedSingle(oldValue))
      // this.dispatchValidateEvent(organId)
      // this.validate()
    },
    // 清除事件
    clearSelect (event) {
      if (this.showCloseIcon) {
        if(this.multiple){
          const oldCopyValues = this.copySelectedMultiple(this.selectedMultiple)
          this.selectedMultiple.splice(0, this.selectedMultiple.length)
          const _model = this.selectedMultiple.map(item => item.id)
          //  数据双向绑定
          this.$emit('input', this.getOrganId(_model))
          // 触发chang事件
          this.$emit('change', this.copySelectedMultiple(this.selectedMultiple), oldCopyValues, event)
          setTimeout(() => this.validate(), 0) // 延迟执行,不然获取到的checkedIds还没有更新会导致验证有问题
        }else{
          const oldValue = this.selectedSingle
          this.selectedSingle = {}
          this.searchStr = ''
          this.$emit('input', '')
          // 触发chang事件
          this.$emit('change', null, this.copySelectedSingle(oldValue))
          // this.dispatchValidateEvent('')
          this.validate()
        }
      }
    },
    // 选中节点触发的事件
    changeChecked (checked, treeNodeData, treeNode, currentCheckedIds, event) {
      // 先清空数据
      const oldCopyValues = this.copySelectedMultiple(this.selectedMultiple)
      // this.selectedMultiple = [];
      // const allChildren = [treeNodeData]
      // if (this.connectParent) { // 树节点改为每次选中都发这个事件了, 这里不用手动获取子节点了, 因为异步的话也拿不到 2019-11-12
        // this.fillAllChildren(treeNodeData, allChildren)
      // }
      if (checked) {
        // const selectedMultipleIds = this.selectedMultiple.map(item => item.id)
        // this.selectedMultiple.push(treeNodeData)
        // for (let i = 0; i < allChildren.length; i++) {
        //   if (this.canCheck(allChildren[i]) && !selectedMultipleIds.includes(allChildren[i].id)) {
        //     this.selectedMultiple.push(allChildren[i])
        //   }
        if (this.canCheck(treeNodeData) && !this.selectedMultiple.map(item => item.id).includes(treeNodeData.id)) {
          this.selectedMultiple.push(treeNodeData)
        }
      } else {
        // for (let i = 0; i < allChildren.length; i++) {
        //   const childData = allChildren[i]
        //   if (!this.canCheck(childData)) {
        //     continue
        //   }
        //   for (let j = 0; j < this.selectedMultiple.length; j++) {
        //     if (this.selectedMultiple[j].id === childData.id) {
        //       this.selectedMultiple.splice(j, 1)
        //       break
        //     }
        //   }
        // }

        if (this.canCheck(treeNodeData)) {
          for (let j = 0; j < this.selectedMultiple.length; j++) {
            if (this.selectedMultiple[j].id === treeNodeData.id) {
              this.selectedMultiple.splice(j, 1)
              break
            }
          }
        }
      }
      if (this.cascade && ['user', 'dept'].includes(this.selectType)) {
        this._delayEmit = true
        this.checkedIds = currentCheckedIds
      } else if (oldCopyValues.length !== this.selectedMultiple.length) {
        this.$emit('input', this.getOrganId(currentCheckedIds))
        this.$emit('change', this.copySelectedMultiple(this.selectedMultiple), oldCopyValues, event)
        // this.dispatchValidateEvent(this.selectedMultiple)
        // this.validate()
      }
    },
    canCheck(nodeData) {
      return this.selectType === 'all' || this.selectType.indexOf(nodeData.customData.type) !== -1
    },
    // fillAllChildren (treeNodeData, allChildren) {
    //   if (treeNodeData.children && treeNodeData.children.length) {
    //     for (let i = 0; i < treeNodeData.children.length; i++) {
    //       allChildren.push(treeNodeData.children[i])
    //       this.fillAllChildren(treeNodeData.children[i], allChildren)
    //     }
    //   }
    // },
    // 监听更新事件
    watchUpdate (multiple) {
      const _this = this
      // 多选
      if (multiple) {
        const oldCopyValues = this.copySelectedMultiple(this.selectedMultiple)
        // 如果多选大于0
        if (_this.$refs.tree.currentCheckedIds.length > 0) {
          // 不能直接清空, 异步情况,初始化绑定了选项, 这个时候树上还没有这个选项节点的情况下,返回的treeNode没有它
          const selectedMultipleTmp = []
          //  循环key,得出完整数据
          _this.$refs.tree.currentCheckedIds.forEach(function (item, index) {
            const nodeData = _this.$refs.tree.getTreeNodeData(item)
            if (nodeData) {
              if (_this.canCheck(nodeData)) {
                selectedMultipleTmp.push(nodeData)
              }
            } else { // 有初始化的数据且树是异步并且没有加载出来
              for (let i = 0; i < _this.selectedMultiple.length; i++) {
                if (_this.selectedMultiple[i].id === item && _this.canCheck(_this.selectedMultiple[i])) {
                  selectedMultipleTmp.push(_this.selectedMultiple[i])
                  break
                }
              }
            }
          })
          _this.selectedMultiple = selectedMultipleTmp
        } else {
          _this.selectedMultiple = []
        }
        if (this._delayEmit) {
          this.$emit('input', this.getOrganId(_this.selectedMultiple.map(item => item.id)))
          this.$emit('change', this.copySelectedMultiple(this.selectedMultiple), oldCopyValues)
          // this.dispatchValidateEvent(this.selectedMultiple)
          this.validate()
        }
        //  单选
      }
      // else {
        // 如果存在，才需要更新
        // if (tree.getActiveTreeNode()) {
          /*
           * let oldValue = this.selectedSingle
           * this.selectedSingle = treeNode.treeNodeData;
           */
          // this.$emit('change', this.copySelectedSingle(this.selectedSingle), this.copySelectedSingle(oldValue));
        // }
      // }
    },
    removeTag (index, event) {
      if (this.disabled) {
        return false
      }
      const oldCopyValues = this.copySelectedMultiple(this.selectedMultiple)
      this.selectedMultiple.splice(index, 1)
      const _model = this.selectedMultiple.map(item => item.id)
      //  数据双向绑定
      this.$emit('input', this.getOrganId(_model))
      // 触发chang事件
      this.$emit('change', this.copySelectedMultiple(this.selectedMultiple), oldCopyValues, event)
      setTimeout(() => this.validate(), 0) // 延迟执行,不然获取到的checkedIds还没有更新会导致验证有问题
    },
    /**
     * #method
     *
     * @name   getSelectedData
     * @returns  selectedData
     * @description   获取当前选中的数据, 多选为数组, 单选为对象
     */
    getSelectedData () {
      if (this.multiple) {
        return this.selectedMultiple.filter(data => this.canCheck(data))
      } else {
        return this.selectedSingle
      }
    },
    requestDataMethod (id, callback, tree, getAllChild) {
      const treeNodeData = tree.getTreeNodeData(id) || {}
      const params = {
        selectType: this.isRightMode ? 'user' : this.selectType,
        selectScope: this.selectScope,
        id: id, // parentId
        lazyLoad: this.lazyLoad
      }
      // 非必须参数优化
      if (this.multiple) params.multiple = this.multiple
      if (this.rootId) params.rootId = this.rootId // 根节点
      if (this.navigation) params.navigation = this.navigation
      if (this.cascade && !this.isRightMode) params.cascade = this.cascade
      if (this.showInvalid) params.showInvalid = this.showInvalid
      if (getAllChild) params.getAllChild = getAllChild // 当异步cascade情况, 树在选中节点后会传递此参数为true, 告知实现者强制获取所有后代节点
      if (treeNodeData && treeNodeData.customData) params.type = treeNodeData.customData.type
      if (this.openOrgans) {
        params.openOrgans = Array.isArray(this.openOrgans) ? this.openOrgans : this.openOrgans.split(',')
      }
      if (this.rightKeys) {
        params.rightKeys = Array.isArray(this.rightKeys) ? this.rightKeys : this.rightKeys.split(',')
      }
      if (this.roleIds) {
        params.roleIds = Array.isArray(this.roleIds) ? this.roleIds : this.roleIds.split(',')
      }
      if (this.listMode) params.listMode = this.listMode
      // 从服务器拉取数据 默认url：artery/organ/children
      Artery.ajax.get(
          this.urlPrefix + this.requestDataUrl,
          {
            params: params,
            paramsSerializer: params => Artery.qs.stringify(params, {arrayFormat: 'repeat'})
          }
      ).then(result => {
        callback(result)
      }).catch(error => {
        console.error('获取组织机构数据失败,error=' + JSON.stringify(error))
        callback([])
      })
    },
    remoteSearchMethod (query, callback) {
      if (!query) {
        return
      }
      const params = {
        selectType: this.selectType,
        selectScope: this.selectScope,
        multiple: this.multiple,
        rootId: this.rootId,
        searchText: query,
        pinyinSearch: this.pinyinSearch,
        showInvalid: this.showInvalid
      }
      // 从服务器拉取数据 默认地址：artery/organ/search
      Artery.ajax.get(this.urlPrefix + this.searchDataUrl, { params: params }).then(result => {
        callback(result)
      }).catch(error => {
        console.error('搜索组织机构数据失败,error=' + JSON.stringify(error))
      })
    },
    dataInit(data) {
      /**
       * #event
       *
       * @name    data-init
       * @param   data       数据
       * @body    console.log(data)
       * @version  1.0.3
       * @description  数据首次初始化完成事件
       */
      this.$emit('data-init', data)
    },
    handleSearchInputClick () {
      // 点击搜索框时，显示树面板
      this.visible = this.visible || true;
    },
    changeSearchInputWidth () {
      this.$nextTick(() => {
        this.searchInputWidth = this.$refs.input.value.length * 12 + 33
        this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
      })
    },
    handleSearchStrChange () {
      // 搜到值没发生改变，直接return，防止请求过多，浪费资源。
      if (this.oldSearchStr == this.searchStr) {
        return;
      }
      if (this.multiple) {
        this.changeSearchInputWidth()
      }
      // 搜索关键词改变时，将搜索项的索引号重置为0
      this.searchItemFocusIndex = 0
      this.oldSearchStr = this.searchStr
      if (!this.searchStr) {
        this.searchData = []
        this.searchDropVisible = false
        return
      }
      // 远程请求数据
      this.remoteSearchMethod(this.searchStr, (_data) => {
        // 异步加载 数据返回有延迟 如果此时关键词被清空，则不需要在处理
        if (!this.searchStr) {
          return
        }
        // 高亮
        _data = this.patternLightWord(_data)
        // 判断数据的长度
        if(_data.length > this.searchShowLimit){
          _data = _data.slice(0, this.searchShowLimit)
        }
        // 赋值
        this.searchData = _data
        // 确保树的下拉显示出来
        this.visible = true
        this.searchDropVisible = true
        this.$nextTick(() => {
          if (this.$refs.searchDrop) {
            this.$refs.searchDrop.update()
          }
        })
      })
    },
    patternLightWord (_data) {
      // 数据匹配度排序：完全匹配在前 + 部分匹配在后
      // 1、全匹配
      var _equalsData = []
      _data = _data.reduce((data, item) => {
        // 如果匹配成功
        if (this.searchStr === item.name || this.pinyinEquals(item)) {
          item.name = String(item.name).replace(this.searchStr, (target) => `<em>${target}</em>`);
          // 添加到数组中
          _equalsData.push(item);
        } else {
          data.push(item)
        }
        return data;
      }, []);

      // 2、部分匹配 正则
      // 正则
      var _matchData = []
      const pattern = new RegExp(this.searchStr.replace(/(\^|\(|\)|\[|\]|\$|\*|\+|\.|\?|\\|\{|\}|\|)/g, '\\$1'), 'igm');
      _matchData = _data.reduce((data, item) => {
        // 如果匹配成功
        if (pattern.test(String(item.name)) || this.pinyinMatch(item)) {
          item.name = String(item.name).replace(pattern, (target) => `<em>${target}</em>`);
          data.push(item);
        }
        return data;
      }, []);
      return _equalsData.concat(_matchData)
    },
    // 拼音全匹配
    pinyinEquals(item){
      if(this.pinyinSearch && item){
        if(item.fullSpell && item.fullSpell.toLowerCase() === this.searchStr.toLowerCase()){
          return true;
        }
        if(item.simpleSpell && item.simpleSpell.toLowerCase() === this.searchStr.toLowerCase()){
          return true;
        }
      }
      return false;
    },
    pinyinMatch(item){
      if(this.pinyinSearch && item){
        if(item.fullSpell && item.fullSpell.toLowerCase().indexOf(this.searchStr.toLowerCase()) != -1){
          return true;
        }
        if(item.simpleSpell && item.simpleSpell.toLowerCase().indexOf(this.searchStr.toLowerCase()) != -1){
          return true;
        }
      }
      return false;
    },
    handleSearchItemClick (item) {
      this.$refs.tree.changeFocusTreeNode(item.id, (treeNode) => {
        if (!treeNode) {
          return;
        }
        // 定位的是叶子节点的话，直接选中
        if (treeNode.treeNodeData.leaf) {
          if (this.multiple) {
            if (!this.selectedMultiple.map(node => node.id).includes(treeNode.treeNodeData.id)) {
              const oldCopyValues = this.copySelectedMultiple(this.selectedMultiple)
              this.selectedMultiple.push(treeNode.treeNodeData)
              this.setValue(this.selectedMultiple.map(node => node.id))
              this.$emit('input', this.getOrganId(this.selectedMultiple.map(item => item.id)))
              this.$emit('change', this.copySelectedMultiple(this.selectedMultiple), oldCopyValues)
            }
          } else {
            if (!this.selectedSingle || this.selectedSingle.id !== treeNode.treeNodeData.id) {
              let oldValue = this.selectedSingle;
              this.selectedSingle = treeNode.treeNodeData;
              this.searchStr = this.selectedSingle.name;
              this.setValue(this.selectedSingle.id, false, true);
              let organId = this.getOrganId(this.selectedSingle.id);
              this.$emit('select', this.copySelectedSingle(this.selectedSingle), treeNode)
              this.$emit('input', organId);
              this.$emit('change', this.copySelectedSingle(this.selectedSingle), this.copySelectedSingle(oldValue))
            } else {
              this.searchStr = treeNode.treeNodeData.name;
            }
          }
        }
        // 多选时，操作后清空搜索关键词
        if (this.multiple) {
          this.searchStr = ''
        }
        // 隐藏搜索下拉
        this.searchDropVisible = false
      });
    },
    handleSearchInputFocus () {
      // 单选获得焦点时，如果值没变则不触发查询
      if (!this.multiple && this.selectedSingle && this.searchStr === this.selectedSingle.name) {
        return;
      }
      this.oldSearchStr = ''
      this.handleSearchStrChange()
    },
    handleSearchInputBlur () {
      // 单选时 搜索框失去焦点，将值还原回选中的值
      if (!this.multiple) {
        this.searchStr = this.selectedSingle ? this.selectedSingle.name : ''
      }
    },
    delHTMLTag (content) {
      return Artery.delHTMLTag(String(content))
    },
    bindSearchEvent () {
      if (this.canSearch) {
        document.addEventListener('keydown', this.handleKeydown);
      }
    },
    handleKeydown (e) {
      const keyCode = e.keyCode;
      if (this.searchDropVisible) {
        // Esc slide-up
        if (keyCode === 27) {
          e.preventDefault();
          this.hideMenu();
        }
        // next
        if (keyCode === 40) {
          e.preventDefault();
          const next = this.searchItemFocusIndex + 1;
          this.searchItemFocusIndex = (this.searchItemFocusIndex === this.searchData.length) ? 1 : next;
        }
        // prev
        if (keyCode === 38) {
          e.preventDefault();
          const prev = this.searchItemFocusIndex - 1;
          this.searchItemFocusIndex = (this.searchItemFocusIndex <= 1) ? this.searchData.length : prev;
        }
        // enter
        if (keyCode === 13) {
          e.preventDefault();
          if (this.searchData.length > 0) {
            if (this.searchData.length === 1) {
              this.handleSearchItemClick(this.searchData[0])
            } else if (this.searchItemFocusIndex > 0) {
              this.handleSearchItemClick(this.searchData[this.searchItemFocusIndex - 1])
            }
          }
        }
      }
    },
    unbindSearchEvent () {
      if (this.canSearch) {
        document.removeEventListener('keydown', this.handleKeydown);
      }
    }
  },
  beforeMount () {
    // 默认设置一次
    if (this.multiple) {
      if (this.value && this.value.length)
        this.setValue(this.value)
    } else if (this.value) {
      this.setValue(this.value)
    }
    // 绑定搜索相关事件
    this.bindSearchEvent();
  },
  mounted () {
    this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
    // if (this.lazyLoad || this.dropAsync) {
    // } else { // 非懒加载, 请求一次
    //   // this.requestDataMethod('', newData => {}, this.$refs.tree, false)
    // }
    /**
     * #event
     *
     * @name    ready
     * @param   tree 当前组织机构树Vue对象
     * @description   组织机构控件准备就绪
     * @body
     */
    this.$emit('ready', this)
  },
  beforeDestroy () {
    //解除搜索相关事件
    this.unbindSearchEvent();
  }
}
